package com.browsesoft.dbtools;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList;

import javax.xml.parsers.SAXParserFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.browsesoft.PropertiesService;

/**
 * 把XML文件内容存储到数据库中，导入时，内容不作任何处理，主要用于公司自己系统之间 数据库的转换
 */
public class XMLToDB {
	/**
	 * 关键字列表，待扩充
	 */
	private LinkedList keyList = new LinkedList();

	/**
	 * 数据库表中需要转变的字段
	 */
	private LinkedList changeFieldes = new LinkedList();

	/**
	 * 数据文件的文件路径名成
	 */
	private String fileName = "";

	/**
	 * 保存需要删除的表的名称
	 */
	HashMap deleteConds = new HashMap();

	/**
	 * 主程序
	 * 
	 * @param args
	 *            参数，格式为: java XMLToDB 文件名，用户名等内容从属性文件中读取
	 */
	public static void main(String[] args) {
		try {
			String path = getPath();
			// 装载属性文件
			PropertiesService.load(path);
			// 装载数据库连接
			ConnectionPool.load();
			// 执行转换
			XMLToDB xd = new XMLToDB(args[0]);
			// 装载关键字
			xd.loadKey();
			// 加载属性文件中的改变字段对象
			xd.loadChangeFieldes();
			xd.save();
			// xd.save("D:/dubin/workspace/DBTranfer/db.xml");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 收集属性文件中配置的删除条件
	 */
	private HashMap collectDelConditions() {
		HashMap result = new HashMap();
		Element elem = (Element) PropertiesService.getDocument()
				.getElementsByTagName("importtables").item(0);
		NodeList nl = elem.getElementsByTagName("table");
		for (int i = 0; i < nl.getLength(); i++) {
			Element oneElem = (Element) nl.item(i);
			String name = oneElem.getAttribute("name");
			// 如果有删除条件，进行参数替换
			String cond = oneElem.getAttribute("delcondition");
			result.put(name, cond);
		}
		return result;
	}

	public static String getPath() {
		return "./properties.xml";
	}

	/**
	 * 构造函数 改构造函数用于导入一个或多个表，每个表可配置删除条件
	 */
	public XMLToDB(String fileName) {
		this.deleteConds = this.collectDelConditions();
		this.fileName = fileName;
	}

	/**
	 * 把文件中的内容存储到数据库中
	 * 
	 */
	public void save() {
		try {
			// 产生document
			SAXParserFactory factory = SAXParserFactory.newInstance();
			InputStream in = new FileInputStream(fileName);
			// this.dropTables();
			System.out.println("droped all tables!");
			System.out.println("begin parse");
			factory.newSAXParser().parse(in, new Handler());
			// 存储根元素
			// Element root = doc.getDocumentElement();
			// this.save(root);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 装载关键字
	 */
	public void loadKey() {
		// 加载关键字，内容待扩充
		keyList.add("use");
		keyList.add("using");
		keyList.add("left");
		keyList.add("user");
	}

	/**
	 * 根据字段链表产生要改变的字段对象链表
	 */
	private void createChangeFieldes(NodeList list) {
		// 清除原来的字段对象
		this.changeFieldes.clear();
		// 临时节点元素
		Node e;
		for (int i = 0; i < list.getLength(); i++) {
			// 取得节点
			e = list.item(i);
			if (e.getNodeType() == Node.ELEMENT_NODE) {
				this.changeFieldes.add(new ChangeField((Element) e));
			}
		}
	}

	/**
	 * 加载要改变的字段
	 */
	public void loadChangeFieldes() {
		// 取得属性文件的文档对象
		Document doc = (Document) PropertiesService.getDocument();
		// 取得属性文件中要转变的字段节点
		NodeList list = doc.getElementsByTagName("changefield");
		Node fieldes = null;
		// 如果有需要改变的字段
		if (list.getLength() > 0) {
			fieldes = list.item(0);
			// 取得该表对应的要改变的字段节点列表
			NodeList changeFieldList = ((Element) fieldes).getChildNodes();
			// 根据字段链表产生要改变的字段对象链表
			this.createChangeFieldes(changeFieldList);
		}
	}

	class Handler extends DefaultHandler {
		/**
		 * 当前记录个数
		 */
		private int count = 0;

		private long start = System.currentTimeMillis();

		private long end;

		/**
		 * 当前所处XML层次，第一层为tables标记，第二层为具体表名，第三层为记录分界符，第四层为字段名
		 */
		private int level = 0;

		/**
		 * 当前表名
		 */
		private String table = null;

		/**
		 * 当前字段名
		 */
		private String name = null;

		/**
		 * 当前字段值
		 */
		private String value = null;

		/**
		 * 当前记录
		 */
		private Hashtable field = null;

		/**
		 * 当前表头信息
		 */
		private Hashtable heads = null;

		public void startElement(String uri, String localName, String qName,
				Attributes attributes) throws SAXException {
			level++;
			if (level == 2) {
				// 得到当前表名
				this.table = qName;
				// 如果有条件，根据条件删除数据，否则，删掉表
				this.dropTable(table);
				System.out.println("beginning tabel:" + this.table);
			}
			// 开始一条记录
			else if (level == 3) {
				// 如果是表头
				if (qName.equals("head")) {
					this.heads = new Hashtable();
				}
				// 否则，是记录
				else {
					this.field = new Hashtable();
				}
			} else if (level == 4) {
				// 得到当前字段名
				this.name = qName.toLowerCase();
				this.value = null;
			}
		}

		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			// 如果表结束
			if (level == 2) {
				count = 0;
			}
			// 如果得到了一条完整记录
			else if (level == 3) {
				try {
					// 如果是表头结束
					if (qName.equals("head")) {
						// 创建表结构
						// DBTools.createTableStruct(this.table, this.heads);
						this.heads = null;
						// this.dataTypes = DBTools.getDataTypes(this.table);
					}
					// 否则，是记录结束
					else {
						DBTools.insert(this.table, this.field);
						this.field = null;
						count++;
						if (count % 1000 == 0) {
							end = System.currentTimeMillis();
							System.out.println(count + "data:" + (end - start));
							start = end;
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			// 如果某字段结束
			else if (level == 4) {
				if (this.value == null) {
					this.value = "";
				}
				// 把转换的回车字符替换
				value = value.replaceAll("#r#", "\r");
				value = value.replaceAll("#n#", "\n");
				// 如果在表头中
				if (this.heads != null) {
					// 产生一个表头
					this.heads.put(name, "");
				} else {
					// 产生一个字段
					this.field.put(name, value);
				}
			}
			level--;
		}

		public void characters(char[] ch, int start, int length)
				throws SAXException {
			// 是字段内容
			if (level == 4) {
				String temp = new String(ch, start, length).trim();
				if (temp != null) {
					if (value == null) {
						value = temp;
					} else {
						value += temp;
					}
				}
			}
		}

		private void dropTable(String tableName) {
			try {
				// 如果该表有删除条件，使用删除
				if (deleteConds.get(tableName) != null
						&& !deleteConds.get(tableName).equals("")) {
					String condition = (String) deleteConds.get(tableName);
					String sql = "delete from " + tableName + " where "
							+ condition;
					DBTools.excuteUpdate(sql);
				} else {
					// 否则，drop表
					DBTools.dropTable(tableName);
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}

}